<?php
declare (strict_types=1);

namespace addons\OssBackup\driver;

use Qiniu\Auth;
use Qiniu\Storage\UploadManager;
use app\admin\controller\Backup;
use addons\OssBackup\exception\OssBackupException;
use GuzzleHttp\Client;

class OssBackup
{
    /**
     * @var string oss备份通讯url
     */
    protected $inspect_url;

    /**
     * @var mixed 配置文件
     */
    protected $config;

    public function __construct()
    {
        $this->inspect_url = 'http://erp.test.daenmende.com/index/backups/inspect';
        $this->config = config('ossBackup');
    }

    /**
     * @return array
     * 原点 2024年5月11日11:07:20 备份自动上传至七牛云OSS
     */
    public function auto(): array
    {
        try {
            $open = $this->correspond(trim($this->config['project_code']));
            if ($open['code'] != 1) {
                throw new OssBackupException($open['msg'], -1);
            }
            $config = $open['data'];
            $result = (new Backup())->ossAdd();
            if ($result['code'] != 1) {
                throw new OssBackupException('备份失败', -1);
            }
            $path = './' . $result['path'];
            $ret = $this->upload($config, $result['name'], $path);
            if (file_exists($path)) unlink($path);
            $downloadUrl = $config['domain'] . $result['name'];
            $result = $this->inspect(
                $config['project_name'],
                $config['project_code'],
                $result['name'],
                $downloadUrl,
                $this->inspect_url
            );
            if ($result['code'] <= 0) {
                throw new OssBackupException('更新备份失败：' . $result['msg'], -1);
            }
            if ($result['code'] == 2) {
                if (!$this->delete($result['deleteName'], $config)) {
                    throw new OssBackupException('文件删除失败', -1);
                }
            }

            return ['code' => 1, 'msg' => '已备份至OSS', 'key' => $ret];
        } catch (\Exception $e) {

            throw new OssBackupException('备份失败：' . $e->getMessage(), -1);
        }
    }

    public function upload($config, $key, $file)
    {
        $auth = new Auth($config['accessKey'], $config['secretKey']);
        $token = $auth->uploadToken($config['bucket']);
        $uploadMgr = new UploadManager();

        list($ret, $err) = $uploadMgr->putFile($token, $key, $file, null,
            'application/octet-stream', false, '', 'v2');
        if ($err) {
            throw new OssBackupException('上传OSS失败', -1);
        }
        return $ret;
    }

    public function correspond($code): array
    {
        $param = [
            'code'       => $code,
            'correspond' => true
        ];
        try {
            $headers = [
                'Content-Type' => 'application/json',
            ];
            $res = (new Client())->request('POST', $this->inspect_url, ['json' => $param, 'headers' => $headers]);

            return json_decode($res->getBody()->getContents(), true);

        } catch (\Exception $e) {
            throw new \Exception($e->getMessage());
        }
    }

    public function inspect($title, $code, $key, $downloadUrl, $inspect_url): array
    {
        $param = [
            'title'       => $title,
            'code'        => $code,
            'backup_name' => $key,
            'backup_url'  => $downloadUrl,
        ];
        try {
            $headers = [
                'Content-Type' => 'application/json',
            ];
            $res = (new Client())->request('POST', $inspect_url, ['json' => $param, 'headers' => $headers]);

            return json_decode($res->getBody()->getContents(), true);

        } catch (\Exception $e) {
            throw new \Exception($e->getMessage());
        }
    }

    public function delete($key, $config): bool
    {
        try {
            $auth = new Auth($config['accessKey'], $config['secretKey']);

            $bucketManager = new \Qiniu\Storage\BucketManager($auth, (new \Qiniu\Config()));
            $err = $bucketManager->delete($config['bucket'], $key);
            if (!$err[1]) {
                return true;
            }
            return false;
        } catch (\Exception $e) {
            return false;
        }

    }
}